package cn.takovh.zpl;

import cn.takovh.zpl.bean.Media;
import cn.takovh.zpl.bean.PlayListItem;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.Window;
import org.dom4j.DocumentException;

import java.util.List;
import java.util.stream.Collectors;

public class Controller {

    private Service service = new Service();

    @FXML
    private VBox box;

    // File
    @FXML
    private MenuItem menuNew;

    @FXML
    private MenuItem menuOpen;

    @FXML
    private MenuItem menuSave;

    @FXML
    private MenuItem menuSaveAs;

    @FXML
    private MenuItem menuQuit;

    // Edit
    @FXML
    private MenuItem menuClear;

    @FXML
    private MenuItem menuAdd;

    @FXML
    private MenuItem menuAddFolder;

    @FXML
    private MenuItem menuDelete;

    @FXML
    private MenuItem menuSelectAll;

    @FXML
    private MenuItem menuUnselectAll;

    @FXML
    private TextField title;

    @FXML
    private TableView<PlayListItem> table;

    @FXML
    private TableColumn<PlayListItem, Boolean> check;

    @FXML
    private TableColumn<PlayListItem, String> trackArtist;

    @FXML
    private TableColumn<PlayListItem, String> trackTitle;

    @FXML
    private TableColumn<PlayListItem, String> albumTitle;

    @FXML
    private TableColumn<PlayListItem, String> src;

    @FXML
    private TableColumn<PlayListItem, Boolean> status;

    @FXML
    private Label itemCount;

    @FXML
    private Label totalDuration;

    @FXML
    void onAdd(ActionEvent event) {
        ObservableList<PlayListItem> tableItems = table.getItems();
        List<PlayListItem> medias = service.addMedias();
        if (!medias.isEmpty()) {
            tableItems.addAll(medias);
        }
    }

    @FXML
    void onAddFolder(ActionEvent event) {
        ObservableList<PlayListItem> tableItems = table.getItems();
        List<PlayListItem> medias = service.addFolder(title);
        if (!medias.isEmpty()) {
            tableItems.addAll(medias);
        }
    }

    @FXML
    void onDelete(ActionEvent event) {

    }

    @FXML
    void onClear(ActionEvent event) {
        table.getItems().clear();
    }

    @FXML
    void onNew(ActionEvent event) {
        service.createZPL();
    }

    @FXML
    void onOpen(ActionEvent event) throws DocumentException {
        ObservableList<PlayListItem> tableItems = table.getItems();
        tableItems.clear();
        service.open(tableItems, title);

    }

    @FXML
    void onSave(ActionEvent event) {
    }

    @FXML
    void onSaveAs(ActionEvent event) {
        ObservableList<PlayListItem> items = table.getItems();
        List<Media> mediaList = items.stream().map(PlayListItem::toMedia).collect(Collectors.toList());
        service.saveZPL(title.getText(), mediaList);
    }

    @FXML
    void onQuit(ActionEvent event) {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("确认退出");
        alert.setHeaderText(null);
        alert.setContentText("放弃更改");
        alert.showAndWait().ifPresent(buttonType -> {
            if (buttonType == ButtonType.OK) {
                Window window = box.getScene().getWindow();
                ((Stage) window).close();
            }
        });
    }

    @FXML
    void onSelectAll(ActionEvent event) {

    }

    @FXML
    void onUnselectAll(ActionEvent event) {

    }

    public void initialize() {
        title.setText("新的播放列表");
        itemCount.setText("0");
        totalDuration.setText("00:00:00");

        check.setCellValueFactory(new PropertyValueFactory<>("check"));
        src.setCellValueFactory(new PropertyValueFactory<>("src"));
        albumTitle.setCellValueFactory(new PropertyValueFactory<>("albumTitle"));
        trackTitle.setCellValueFactory(new PropertyValueFactory<>("trackTitle"));
        trackArtist.setCellValueFactory(new PropertyValueFactory<>("trackArtist"));
        status.setCellValueFactory(new PropertyValueFactory<>("status"));

        ObservableList<PlayListItem> playListItemList = FXCollections.observableArrayList();
        table.setItems(playListItemList);

        playListItemList.addListener(new ListChangeListener<PlayListItem>() {
            @Override
            public void onChanged(Change<? extends PlayListItem> c) {
                while (c.next()) {
                    boolean added = c.wasAdded();
                    List<? extends PlayListItem> changed = added ? c.getAddedSubList() : c.getRemoved();
                    doChange(added, changed);
                }
            }

            private void doChange(boolean added, List<? extends PlayListItem> list) {
                int count = Integer.parseInt(itemCount.getText());
                count = added ? count + list.size() : count - list.size();
                itemCount.setText(String.valueOf(count));
                long originMillisecond = service.timeToMillisecond(totalDuration.getText());
                Integer changed = list.stream().map(PlayListItem::getDuration).reduce(0, Integer::sum);
                originMillisecond = added ? originMillisecond + changed : originMillisecond - changed;
                totalDuration.setText(service.millisecondToTime(originMillisecond));
            }
        });

        box.addEventFilter(KeyEvent.KEY_RELEASED, this::boxKeyReleasedEvent);
    }


    private final KeyCombination ctrlO = new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN);
    private final KeyCombination ctrlS = new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN);
    private final KeyCombination ctrlC = new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_DOWN);
    private final KeyCombination ctrlA = new KeyCodeCombination(KeyCode.A, KeyCombination.CONTROL_DOWN);
    private final KeyCombination ctrlD = new KeyCodeCombination(KeyCode.D, KeyCombination.CONTROL_DOWN);
    private final KeyCombination ctrlQ = new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN);

    private void boxKeyReleasedEvent(KeyEvent e) {
        try {
            if (ctrlO.match(e)) {
                onOpen(null);
            } else if (ctrlS.match(e)) {
                onSave(null);
            } else if (ctrlC.match(e)) {
                onClear(null);
            } else if (ctrlA.match(e)) {
                onAdd(null);
            } else if (ctrlD.match(e)) {
                onDelete(null);
            } else if (ctrlQ.match(e)) {
                onQuit(null);
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

}
